home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / CONTRIB / HANOI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  8.7 KB  |  470 lines

  1.  
  2. /* hanoi.c - written by Greg Humphreys while an intern at SGI */
  3.  
  4. #include <GL/glut.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <stdlib.h>
  8.  
  9. double WIDTH = 800;
  10. double HEIGHT = 800;
  11.  
  12. GLboolean motion = GL_TRUE;
  13. GLboolean back_wall = GL_FALSE;
  14. GLint xangle = 0, yangle = 0;
  15. GLint xlangle = 0, ylangle = 0;
  16.  
  17. #define other(i,j) (6-(i+j))
  18. #define wallz -(WIDTH/2)
  19. #define DISK_HEIGHT 20
  20. int NUM_DISKS = 11;
  21. #define CONE NUM_DISKS+1
  22. #define WALL CONE + 1
  23. #define HANOI_SOLVE 0
  24. #define HANOI_QUIT 1
  25. #define HANOI_LIGHTING 2
  26. #define HANOI_WALL 3
  27. #define HANOI_FOG 4
  28.  
  29. GLfloat lightOneDirection[] =
  30. {0, 0, -1};
  31. GLfloat lightOnePosition[] =
  32. {200, 100, 300, 1};
  33. GLfloat lightOneColor[] =
  34. {1.0, 1.0, 0.5, 1.0};
  35.  
  36. GLfloat lightTwoDirection[] =
  37. {0, 0, -1};
  38. GLfloat lightTwoPosition[] =
  39. {600, 100, 300, 1};
  40. GLfloat lightTwoColor[] =
  41. {1.0, 0.0, 0.3, 1.0};
  42.  
  43. GLfloat lightZeroPosition[] =
  44. {400, 200, 300, 1};
  45. GLfloat lightZeroColor[] =
  46. {.3, .3, .3, .3};
  47.  
  48. GLfloat diskColor[] =
  49. {1.0, 1.0, 1.0, .8}, poleColor[] =
  50. {1.0, 0.2, 0.2, .8};
  51.  
  52. typedef struct stack_node {
  53.   int size;
  54.   struct stack_node *next;
  55. } stack_node;
  56.  
  57. typedef struct stack {
  58.   struct stack_node *head;
  59.   int depth;
  60. } stack;
  61.  
  62. stack poles[4];
  63.  
  64. void 
  65. push(int which, int size)
  66. {
  67.   stack_node *node = malloc(sizeof(stack_node));
  68.   if (!node) {
  69.     fprintf(stderr, "out of memory!\n");
  70.     exit(-1);
  71.   }
  72.   node->size = size;
  73.   node->next = poles[which].head;
  74.   poles[which].head = node;
  75.   poles[which].depth++;
  76. }
  77.  
  78. int 
  79. pop(int which)
  80. {
  81.   int retval = poles[which].head->size;
  82.   stack_node *temp = poles[which].head;
  83.   poles[which].head = poles[which].head->next;
  84.   poles[which].depth--;
  85.   free(temp);
  86.   return retval;
  87. }
  88.  
  89. typedef struct move_node {
  90.   int t, f;
  91.   struct move_node *next;
  92.   struct move_node *prev;
  93. } move_node;
  94.  
  95. typedef struct move_stack {
  96.   int depth;
  97.   struct move_node *head, *tail;
  98. } move_stack;
  99.  
  100. move_stack moves;
  101.  
  102. void 
  103. init(void)
  104. {
  105.   int i;
  106.   for (i = 0; i < 4; i++) {
  107.     poles[i].head = NULL;
  108.     poles[i].depth = 0;
  109.   }
  110.   moves.head = NULL;
  111.   moves.tail = NULL;
  112.   moves.depth = 0;
  113.  
  114.   for (i = 1; i <= NUM_DISKS; i++) {
  115.     glNewList(i, GL_COMPILE);
  116.     {
  117.       glutSolidTorus(DISK_HEIGHT / 2, 5 * i, 15, 15);
  118.     }
  119.     glEndList();
  120.   }
  121.   glNewList(CONE, GL_COMPILE);
  122.   {
  123.     glutSolidCone(10, (NUM_DISKS + 1) * DISK_HEIGHT, 20, 20);
  124.   }
  125.   glEndList();
  126. }
  127.  
  128. void 
  129. mpop(void)
  130. {
  131.   move_node *temp = moves.head;
  132.   moves.head = moves.head->next;
  133.   free(temp);
  134.   moves.depth--;
  135. }
  136.  
  137. void 
  138. mpush(int t, int f)
  139. {
  140.   move_node *node = malloc(sizeof(move_node));
  141.   if (!node) {
  142.     fprintf(stderr, "Out of memory!\n");
  143.     exit(-1);
  144.   }
  145.   node->t = t;
  146.   node->f = f;
  147.   node->next = NULL;
  148.   node->prev = moves.tail;
  149.   if (moves.tail)
  150.     moves.tail->next = node;
  151.   moves.tail = node;
  152.   if (!moves.head)
  153.     moves.head = moves.tail;
  154.   moves.depth++;
  155. }
  156.  
  157. /* ARGSUSED1 */
  158. void 
  159. keyboard(unsigned char key, int x, int y)
  160. {
  161.   switch (key) {
  162.   case 27:             /* ESC */
  163.   case 'q':
  164.   case 'Q':
  165.     exit(0);
  166.   }
  167. }
  168.  
  169. void 
  170. update(void)
  171. {
  172.   glutPostRedisplay();
  173. }
  174.  
  175. void 
  176. DrawPost(int xcenter)
  177. {
  178.   glPushMatrix();
  179.   {
  180.     glTranslatef(xcenter, 0, 0);
  181.     glRotatef(90, -1, 0, 0);
  182.     glCallList(CONE);
  183.   } glPopMatrix();
  184. }
  185.  
  186. void 
  187. DrawPosts(void)
  188. {
  189.   glColor3fv(poleColor);
  190.   glLineWidth(10);
  191.   glMaterialfv(GL_FRONT, GL_DIFFUSE, poleColor);
  192.   DrawPost((int) WIDTH / 4);
  193.   DrawPost(2 * (int) WIDTH / 4);
  194.   DrawPost(3 * (int) WIDTH / 4);
  195. }
  196.  
  197. void 
  198. DrawDisk(int xcenter, int ycenter, int size)
  199. {
  200.   glPushMatrix();
  201.   {
  202.     glTranslatef(xcenter, ycenter, 0);
  203.     glRotatef(90, 1, 0, 0);
  204.     glCallList(size);
  205.   } glPopMatrix();
  206. }
  207.  
  208. void 
  209. DrawDooDads(void)
  210. {
  211.   int i;
  212.   stack_node *temp;
  213.   int xcenter, ycenter;
  214.   glColor3fv(diskColor);
  215.   glMaterialfv(GL_FRONT, GL_DIFFUSE, diskColor);
  216.   for (i = 1; i <= 3; i++) {
  217.     xcenter = i * WIDTH / 4;
  218.     for (temp = poles[i].head, ycenter = DISK_HEIGHT * poles[i].depth - DISK_HEIGHT / 2; temp; temp = temp->next, ycenter -= DISK_HEIGHT) {
  219.       DrawDisk(xcenter, ycenter, temp->size);
  220.     }
  221.   }
  222. }
  223.  
  224. #define MOVE(t,f) mpush((t),(f))
  225.  
  226. static void
  227. mov(int n, int f, int t)
  228. {
  229.   int o;
  230.  
  231.   if (n == 1) {
  232.     MOVE(t, f);
  233.     return;
  234.   }
  235.   o = other(f, t);
  236.   mov(n - 1, f, o);
  237.   mov(1, f, t);
  238.   mov(n - 1, o, t);
  239. }
  240.  
  241. GLfloat wallcolor[] =
  242. {0, .3, 1, 1};
  243.  
  244. void 
  245. DrawWall(void)
  246. {
  247.   int i;
  248.   int j;
  249.   glColor3fv(wallcolor);
  250.   for (i = 0; i < WIDTH; i += 10) {
  251.     for (j = 0; j < HEIGHT; j += 10) {
  252.       glBegin(GL_POLYGON);
  253.       {
  254.         glNormal3f(0, 0, 1);
  255.         glVertex3f(i + 10, j, wallz);
  256.         glVertex3f(i + 10, j + 10, wallz);
  257.         glVertex3f(i, j + 10, wallz);
  258.         glVertex3f(i, j, wallz);
  259.       }
  260.       glEnd();
  261.     }
  262.   }
  263. }
  264.  
  265. void 
  266. draw(void)
  267. {
  268.   int t, f;
  269.  
  270.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  271.  
  272.   if (back_wall) {
  273.     glMaterialfv(GL_FRONT, GL_DIFFUSE, wallcolor);
  274.     DrawWall();
  275.   }
  276.   glPushMatrix();
  277.   {
  278.     glTranslatef(WIDTH / 2, HEIGHT / 2, 0);
  279.     glRotatef(xlangle, 0, 1, 0);
  280.     glRotatef(ylangle, 1, 0, 0);
  281.     glTranslatef(-WIDTH / 2, -HEIGHT / 2, 0);
  282.     glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  283.   }
  284.   glPopMatrix();
  285.  
  286.   glPushMatrix();
  287.   {
  288.     glTranslatef(WIDTH / 2, HEIGHT / 2, 0);
  289.     glRotatef(xangle, 0, 1, 0);
  290.     glRotatef(yangle, 1, 0, 0);
  291.     glTranslatef(-WIDTH / 2, -HEIGHT / 2, 0);
  292.     DrawPosts();
  293.     DrawDooDads();
  294.   }
  295.   glPopMatrix();
  296.   if (motion && moves.depth) {
  297.     t = moves.head->t;
  298.     f = moves.head->f;
  299.     push(t, pop(f));
  300.     mpop();
  301.   }
  302.   glutSwapBuffers();
  303. }
  304.  
  305. void 
  306. hanoi_menu(int value)
  307. {
  308.   switch (value) {
  309.   case HANOI_SOLVE:
  310.     motion = !motion;
  311.     if(motion) {
  312.       glutIdleFunc(update);
  313.     } else {
  314.       glutIdleFunc(NULL);
  315.     }
  316.     break;
  317.   case HANOI_LIGHTING:
  318.     if (glIsEnabled(GL_LIGHTING))
  319.       glDisable(GL_LIGHTING);
  320.     else
  321.       glEnable(GL_LIGHTING);
  322.     break;
  323.   case HANOI_WALL:
  324.     back_wall = !back_wall;
  325.     break;
  326.   case HANOI_FOG:
  327.     if (glIsEnabled(GL_FOG))
  328.       glDisable(GL_FOG);
  329.     else {
  330.       glEnable(GL_FOG);
  331.       glFogi(GL_FOG_MODE, GL_EXP);
  332.       glFogf(GL_FOG_DENSITY, .01);
  333.     }
  334.     break;
  335.   case HANOI_QUIT:
  336.     exit(0);
  337.     break;
  338.   }
  339.   glutPostRedisplay();
  340. }
  341.  
  342. int oldx, oldy;
  343.  
  344. GLboolean leftb = GL_FALSE, middleb = GL_FALSE;
  345.  
  346. void 
  347. hanoi_mouse(int button, int state, int x, int y)
  348. {
  349.   if (button == GLUT_LEFT_BUTTON) {
  350.     oldx = x;
  351.     oldy = y;
  352.     if (state == GLUT_DOWN)
  353.       leftb = GL_TRUE;
  354.     else
  355.       leftb = GL_FALSE;
  356.   }
  357.   if (button == GLUT_MIDDLE_BUTTON) {
  358.     oldx = x;
  359.     oldy = y;
  360.     if (state == GLUT_DOWN)
  361.       middleb = GL_TRUE;
  362.     else
  363.       middleb = GL_FALSE;
  364.   }
  365. }
  366.  
  367. void 
  368. hanoi_visibility(int state)
  369. {
  370.   if (state == GLUT_VISIBLE && motion) {
  371.     glutIdleFunc(update);
  372.   } else {
  373.     glutIdleFunc(NULL);
  374.   }
  375. }
  376.  
  377. void 
  378. hanoi_motion(int x, int y)
  379. {
  380.   if (leftb) {
  381.     xangle -= (x - oldx);
  382.     yangle -= (y - oldy);
  383.   }
  384.   if (middleb) {
  385.     xlangle -= (x - oldx);
  386.     ylangle -= (y - oldy);
  387.   }
  388.   oldx = x;
  389.   oldy = y;
  390.   glutPostRedisplay();
  391. }
  392.  
  393. int 
  394. main(int argc, char *argv[])
  395. {
  396.   int i;
  397.  
  398.   glutInit(&argc, argv);
  399.   for(i=1; i<argc; i++) {
  400.     if(!strcmp("-n", argv[i])) {
  401.       i++;
  402.       if(i >= argc) {
  403.     printf("hanoi: number after -n is required\n");
  404.     exit(1);
  405.       }
  406.       NUM_DISKS = atoi(argv[i]);
  407.     }
  408.   }
  409.  
  410.   glutInitWindowSize((int) WIDTH, (int) HEIGHT);
  411.   glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
  412.  
  413.   glutCreateWindow("Hanoi");
  414.  
  415.   glutDisplayFunc(draw);
  416.   glutKeyboardFunc(keyboard);
  417.  
  418.   glViewport(0, 0, (GLsizei) WIDTH, (GLsizei) HEIGHT);
  419.   glMatrixMode(GL_PROJECTION);
  420.   glLoadIdentity();
  421.   glOrtho(0, WIDTH, 0, HEIGHT, -10000, 10000);
  422.   glMatrixMode(GL_MODELVIEW);
  423.   glLoadIdentity();
  424.   glClearColor(0, 0, 0, 0);
  425.   glClearDepth(1.0);
  426.  
  427.   glEnable(GL_CULL_FACE);
  428.   glEnable(GL_DEPTH_TEST);
  429.  
  430. /*  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);  */
  431.  
  432.   glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  433.   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  434.   glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 10);
  435.   glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, lightOneDirection);
  436.   glEnable(GL_LIGHT1);
  437.  
  438.   glLightfv(GL_LIGHT2, GL_POSITION, lightTwoPosition);
  439.   glLightfv(GL_LIGHT2, GL_DIFFUSE, lightTwoColor);
  440. /*  glLightf(GL_LIGHT2,GL_LINEAR_ATTENUATION,.005); */
  441.   glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 10);
  442.   glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, lightTwoDirection);
  443.   glEnable(GL_LIGHT2);
  444.  
  445.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  446.   glEnable(GL_LIGHT0);
  447.  
  448.   glEnable(GL_LIGHTING);
  449.  
  450.   glutMouseFunc(hanoi_mouse);
  451.   glutMotionFunc(hanoi_motion);
  452.   glutVisibilityFunc(hanoi_visibility);
  453.  
  454.   glutCreateMenu(hanoi_menu);
  455.   glutAddMenuEntry("Solve", HANOI_SOLVE);
  456.   glutAddMenuEntry("Lighting", HANOI_LIGHTING);
  457.   glutAddMenuEntry("Back Wall", HANOI_WALL);
  458.   glutAddMenuEntry("Fog", HANOI_FOG);
  459.   glutAddMenuEntry("Quit", HANOI_QUIT);
  460.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  461.   init();
  462.  
  463.   for (i = 0; i < NUM_DISKS; i++)
  464.     push(1, NUM_DISKS - i);
  465.   mov(NUM_DISKS, 1, 3);
  466.  
  467.   glutMainLoop();
  468.   return 0;             /* ANSI C requires main to return int. */
  469. }
  470.